#include "Config.h"
#include "Common/TimeUtil.h"
#include "Common/Base64.h"
#include "GameReportManager.h"
#include "DBCache/DBDataExecHelper.h"
#include "Player.h"
#include "Server.h"
#include "DB/DBExecutor.h"
#include  "Server/IDGenerator.h"

GameReportManager::GameReportManager()
{

}

GameReportManager::~GameReportManager()
{
	//TODO :
}

void GReportCell::save()
{
	char buffer[1024] = { 0 };
	snprintf(buffer, sizeof(buffer), "INSERT INTO `game_report`(`id`, `rid`, `p0_id`, `p0_nick`, `p0_score`, `p1_id`, `p1_nick`, `p1_score`, `p2_id`, `p2_nick`, `p2_score`, `p3_id`, `p3_nick`, `p3_score`, `time`) VALUES(%u, %u, %"I64_FMT"u, '%s', %d, %"I64_FMT"u, '%s', %d, %"I64_FMT"u, '%s', %d, %"I64_FMT"u, '%s', %d, %u)", \
		_id, _rid, _gpds[0]->_uid, _gpds[0]->_nick.c_str(), _gpds[0]->_score, _gpds[1]->_uid, _gpds[1]->_nick.c_str(), _gpds[1]->_score, _gpds[2]->_uid, _gpds[2]->_nick.c_str(), _gpds[2]->_score, _gpds[3]->_uid, _gpds[3]->_nick.c_str(), _gpds[3]->_score, _time);
	DB().PushObjectUpdateData(buffer);
}

void GameReportManager::add(GReportCell * cell)
{
	_cells.insert( std::make_pair( cell->_id, cell ) );
}

UInt8 GameReportManager::getGameReport( UInt32 id, std::vector<UInt8>& reports )
{
	auto found = _cells.find( id );
	if (found == _cells.end())
		return 1;
	GReportCell * cell = found->second;
	std::string filePath = cfg.getReportPath() + "/" + TimeUtil::GetFormatTime(cell->_time) + "/" + Itoa<UInt32>(id);
	FILE * f = fopen(filePath.c_str(), "rb");
	if (f == NULL)
		return 1;
	fseek(f, 0, SEEK_END);
	size_t size = ftell(f);
	fseek(f, 0, SEEK_SET);
	reports.resize(size);
	fread(&reports[0], 1, size, f);
	fclose(f);
	return 0;
}

void GameReportManager::update( UInt32 now )
{
	UInt32 expireTime = now - TimeUtil::DaySec;
	for (auto itr = _cells.begin(); itr != _cells.end(); )
	{
		GReportCell * cell = itr->second;
		if (cell->_time <= expireTime)
		{
			SAFE_DELETE(cell);
			_cells.erase(itr++);
		}
		else
			++itr; 
	}
	//
	std::unique_ptr<DBExecutor> execu(gObjectDBConnectionMgr->GetExecutor());
	if (execu.get() == NULL || !execu->isConnected()) return;
	execu->Execute2("DELETE FROM `game_report` WHERE `time` < %u", expireTime);
}

bool GameReportManager::load()
{
	std::unique_ptr<DBExecutor> execu(gObjectDBConnectionMgr->GetExecutor());
	if (execu.get() == NULL || !execu->isConnected()) return false;
	//
	UInt32 maxId = 0;
	execu->Extract( "SELECT max(`id`) FROM `game_report`", maxId );
	gReportIDGen.setMaxId(maxId);
	//
	UInt32 expireTime = TimeUtil::Now() - TimeUtil::DaySec;
	execu->Execute2("DELETE FROM `game_report` WHERE `time` < %u", expireTime);
	//
	DBGReportData dgrd;
	if (execu->Prepare("SELECT `id`, `p0_id`, `p0_nick`, `p0_score`, `p1_id`, `p1_nick`, `p1_score`, `p2_id`, `p2_nick`, `p2_score`, `p3_id`, `p3_nick`, `p3_score`, `time` FROM `game_report`", dgrd) != DB_OK)
		return false;
	while (execu->Next() == DB_OK)
	{
		GReportCell * cell = new GReportCell();
		cell->_id = dgrd._id;
		cell->_time = dgrd._time;
		for (Int8 i = 0; i < 4; ++i)
		{
			cell->_gpds[i] = new GPlayerData();
			cell->_gpds[i]->_uid = dgrd._gpds[i]._uid;
			unsigned char buffer[1024] = { 0 };
			unsigned long len = 1024;
			CBase64::Decode(dgrd._gpds[i]._nick, buffer, &len);
			cell->_gpds[i]->_nick = reinterpret_cast<char *>(buffer);
			cell->_gpds[i]->_score = dgrd._gpds[i]._score;
		}
		_cells.insert( std::make_pair(cell->_id, cell) );
	}
	return true;
}

std::multimap<UInt32, UInt32> GameReportManager::getOnePlayerGameReport(UInt64 pid)
{
	std::multimap<UInt32, UInt32> ids;
	GReportCell * cell = nullptr;
	for (auto itr = _cells.begin(); itr != _cells.end(); ++itr)
	{
		cell = itr->second;
		for (UInt8 i = 0; i < 4; ++i)
		{
			if (cell->_gpds[i]->_uid == pid)
			{
				ids.insert(std::make_pair(cell->_time, cell->_id));
				break;
			}
		}
	}
	return ids;
}

void GameReportManager::appendReportListData(std::vector<UInt32>& rptIds, Stream& st)
{
	UInt8 c = 0;
	size_t stPos = st.size();
	st << static_cast<UInt8>(0);
	for (size_t i = 0; i < rptIds.size(); ++i)
	{
		GReportCell * cell = GRM()->getGReport(rptIds[i]);
		if (cell != nullptr)
		{
			++c;
			cell->appendData(st);
		}
	}
	st.data<UInt8>(stPos) = c;
}


GReportCell * GameReportManager::getGReport(UInt32 id)
{
	auto found = _cells.find( id );
	return found == _cells.end() ? nullptr : found->second;
}